package at.fhooe.stefanirndorfer.controller;

import static at.fhooe.stefanirndorfer.utilities.Utilities.NE;
import static at.fhooe.stefanirndorfer.utilities.Utilities.NW;
import static at.fhooe.stefanirndorfer.utilities.Utilities.SE;
import static at.fhooe.stefanirndorfer.utilities.Utilities.SW;

import java.util.ArrayList;
import java.util.List;

import org.lwjgl.input.Keyboard;

import at.fhooe.stefanirndorfer.entity.EntityManager;
import at.fhooe.stefanirndorfer.event.GeometryChangedEvent;
import at.fhooe.stefanirndorfer.game.Game;
import at.fhooe.stefanirndorfer.input.KeyInputListener;
import at.fhooe.stefanirndorfer.labeling.Labeling_Manager;
import at.fhooe.stefanirndorfer.labeling.Region;
import at.fhooe.stefanirndorfer.labeling.Region_Manager;
import at.fhooe.stefanirndorfer.quadtree.QuadTreeNode;
import at.fhooe.stefanirndorfer.quadtree.QuadTree_Manager;
import at.fhooe.stefanirndorfer.transformation.GlobalTransformationData;
import at.fhooe.stefanirndorfer.walls.ConcreteWall;
import at.fhooe.stefanirndorfer.walls.GeometrySetups;
import at.fhooe.stefanirndorfer.walls.Wall;

public class Controller implements KeyInputListener{
	
	
	private QuadTreeNode qtree;
	private boolean geom_generated;
	private boolean regionsGenerated;
	
	public Controller(){
		geom_generated = false;
		regionsGenerated = false;
		qtree = null;
		setUpKeyInputListener();
		
		printKeyCommands();
	}
	

	private void printKeyCommands() {
		System.out.println("//__________________//");
		System.out.println("//__________________//");
		System.out.println("Key commands:");
		System.out.println("1: generate geometry");
		System.out.println("2: generate quad tree");
		System.out.println("3: label quadtree (not yet cleaned up)");
		System.out.println("4: label quadtree (clean up merges array)");
		System.out.println("5: remove a wall (dont forget to clean up by hitting 4 afterwards)");
		System.out.println("6: add a wall (dont forget to clean up by hitting 4 afterwards)");
		System.out.println("7: add a wall that adds a region (dont forget to clean up by hitting 4 afterwards)");
		
		System.out.println("");
		System.out.println("c: toggle leaf colors (label-color, single leaf color)");
		System.out.println("left mouse button: if labeled, clicke leaf to read its regions id on the console.)");
		
		System.out.println("//__________________//");
		System.out.println("//__________________//");
		
	}


	@Override
	public void setUpKeyInputListener() {
		Game.getInstance().getInputManager().addKeyListener(this);
	}

	@Override
	public void tearDownKeyInputListener(KeyInputListener il) {
		Game.getInstance().getInputManager().removeKeyListener(this);
	}

	@Override
	public void processKeyInput(int eventKey, boolean keyDown) {
		if(keyDown){
			if(eventKey == Keyboard.KEY_1 && keyDown && !geom_generated){
				setUpGeometry();
			}
			if(eventKey == Keyboard.KEY_2 && keyDown && geom_generated && qtree == null){
				generateQuadTree();
			}
			if(eventKey == Keyboard.KEY_3 && keyDown && qtree != null && !regionsGenerated){
				generateRegions();
			}
			if(eventKey == Keyboard.KEY_4 && keyDown && qtree != null && regionsGenerated){
				cleanUpMergesArray();
			}
			if(eventKey == Keyboard.KEY_5 && keyDown && qtree != null && regionsGenerated){
				removeWall();
			}
			if(eventKey == Keyboard.KEY_6 && keyDown && qtree != null && regionsGenerated){
				addWall();
			}
			if(eventKey == Keyboard.KEY_7 && keyDown && qtree != null && regionsGenerated){
				addWallThatAddsRegion();
			}
			
			if(eventKey == Keyboard.KEY_C && qtree != null && geom_generated){
				toggleLeafColors(qtree);
			}
			
		}
	}

	private void addWallThatAddsRegion() {
		ArrayList<Wall> addedWalls = new ArrayList<Wall>();
		
		Wall newWall = new ConcreteWall(20, 100, -150, -100);
		addedWalls.add(newWall);
		
		Wall newWall2 = new ConcreteWall(200, 20, -250, -100);
		addedWalls.add(newWall2);
		
		Game.getInstance().getEvent_manager().dispatchEvent(new GeometryChangedEvent(addedWalls));
	}


	private void addWall() {
		Wall newWall = new ConcreteWall(50, 50, -250, -220);
		ArrayList<Wall> addedWalls = new ArrayList<Wall>();
		addedWalls.add(newWall);
		
		Game.getInstance().getEvent_manager().dispatchEvent(new GeometryChangedEvent(addedWalls));
	}


	/**
	 * removes walls and invokes the handling for this changing
	 */
	private void removeWall() {
		EntityManager em =  Game.getInstance().getEntityManager();
		ArrayList<Wall> wallsToBeRemoved = new ArrayList<Wall>();
		
		Wall w = em.checkWallCollisions(70, 200);
		if(w != null){
			wallsToBeRemoved.add(w);
			w.tearDownEntity();
		}
		if(wallsToBeRemoved.size() > 0)
		Game.getInstance().getEvent_manager().dispatchEvent(new GeometryChangedEvent(wallsToBeRemoved));
				
	}


	private void cleanUpMergesArray() {
		
		Game.getInstance().getLabelingManager().merge();
		Game.getInstance().getRegionManager().findAllBorderLeafs();
		Game.getInstance().getRegionManager().calculateGlobalConnectivityData();
		
		printStats();
	}


	private void printStats() {
		
		Region_Manager rm = Game.getInstance().getRegionManager();
		List<Region> regions = rm.getRegions();
		
		for(Region r :regions){
			System.out.println(r.getLeafs().size());
		}
	}


	private void toggleLeafColors(QuadTreeNode n) {
		if(n.getChildNodes()[0] != null){
			toggleLeafColors(n.getChildNodes()[NW]);
			toggleLeafColors(n.getChildNodes()[NE]);
			toggleLeafColors(n.getChildNodes()[SE]);
			toggleLeafColors(n.getChildNodes()[SW]);
		}else{
			n.toggleColors();
		}
	}


	private void generateRegions() {
		Labeling_Manager l = Game.getInstance().getLabelingManager();
		l.initialize(qtree);
		regionsGenerated = true;
	}


	private void generateQuadTree() {
		QuadTree_Manager qtm = Game.getInstance().getQuadTreeManager();
		qtm.initialize(4,(int)( 700*GlobalTransformationData.SCALE), 10, new double[]{0.0, 0.0});
		qtree = qtm.getRootNode();
	}

	private void setUpGeometry() {
		GeometrySetups.GeometryOne();
		GeometrySetups.SimpleExampleGeometry();
		//GeometrySetups.GeometryTwo();
		geom_generated = true;
	}

	@Override
	public String getId() {
		// TODO Auto-generated method stub
		return null;
	}

}
